package com.tang.framework.log.support;

import com.tang.common.constant.Constant;
import com.tang.common.properties.sys.CoolTeaProperties;
import com.tang.common.utils.CoolUtil;
import com.tang.framework.async.AbstractAsyncHandler;
import com.tang.framework.async.model.AsyncLog;
import com.tang.framework.log.enums.LogType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * @Author tang jun liang
 * @Date 2023/5/20 16:28
 */
@Aspect
@Component
@Slf4j
public class RequestLogAspect {


    private final static String LOG_PREFIX = "=============================开始=============================";

    private final static String LOG_SUFFIX = "=============================结束=============================";

    @Resource
    private HttpServletRequest request;

    @Resource
    private AbstractAsyncHandler<AsyncLog> asyncLogHandler;

    @Resource
    private CoolTeaProperties coolTeaProperties;




    @Pointcut("within(com.tang.portal.controller.admin..*) &&  !within(com.tang.portal.controller.admin.log..*) ")
    public void adminPointCut() {

    }

    @Pointcut("within(com.tang.portal.controller..*) && !within(com.tang.portal.controller.admin..*)")
    public void appPointCut() {
    }


    @Around(value = "adminPointCut()")
    public Object adminAround(ProceedingJoinPoint joinPoint) throws Throwable {
        return proceed(joinPoint, LogType.ADMIN);
    }


    @Around(value = "appPointCut()")
    public Object appAround(ProceedingJoinPoint joinPoint) throws Throwable {
        return proceed(joinPoint, LogType.APP);
    }


    private Object proceed(ProceedingJoinPoint joinPoint, LogType logType) throws Throwable {
        AsyncLog asyncLog = new AsyncLog();
        if (coolTeaProperties.getPrintRequestLog()) {
            log.info(LOG_PREFIX);
        }
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        String requestUri = request.getRequestURI().replace("/Tag/", "");
        String params = CoolUtil.getRequestParam(methodSignature.getParameterNames(), joinPoint.getArgs());
        String token = request.getHeader(Constant.TOKEN_HEADER);
        long begin = System.currentTimeMillis();
        Throwable throwable = null;
        Object returnObject = null;
        asyncLog.setError(false);
        LocalDateTime executeTime = LocalDateTime.now();
        try {
            if (joinPoint.getArgs().length == 0) {
                returnObject = joinPoint.proceed();
            } else {
                returnObject = joinPoint.proceed(joinPoint.getArgs());
            }
        } catch (Throwable t) {
            StringBuilder stringBuilder = new StringBuilder();
            for (StackTraceElement trace : t.getStackTrace()) {
                stringBuilder.append(trace);
                stringBuilder.append("\n");
            }
            asyncLog.setErrorMessage(t.getMessage());
            asyncLog.setErrorStack(stringBuilder.toString());
            asyncLog.setError(true);
            throwable = t;
        }
        long end = System.currentTimeMillis();
        asyncLog.setLogType(logType);
        asyncLog.setParams(params);
        asyncLog.setRequestUri(requestUri);
        asyncLog.setToken(token);
        asyncLog.setClassName(joinPoint.getTarget().getClass().getSimpleName());
        asyncLog.setMethodName(method.getName());
        asyncLog.setTime(end - begin);
        asyncLog.setExecuteTime(executeTime);
        asyncLogHandler.async(asyncLog);
        if (coolTeaProperties.getPrintRequestLog()) {
            log.info("请求路径: {}, 请求方法: {}, 参数: {}, token: {}, 响应时间: {}", requestUri, method.getName(), params, token, end - begin);
        }
        if (Objects.nonNull(throwable)) {
            throw throwable;
        }
        if (coolTeaProperties.getPrintRequestLog()) {
            log.info(LOG_SUFFIX);
        }
        return returnObject;
    }
}
